﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Text.RegularExpressions;

namespace AlbumArtOrganizer.Plugins.FileSystem.AlbumScanner
{
    public class AlbumScanner : AlbumArtOrganizer.AlbumScanner.AlbumScanner
    {
        ICollection<AlbumArtOrganizer.Model.IAlbum> _foundAlbums = null;

        public AlbumScanner()
            : base()
        {
            _foundAlbums = new List<AlbumArtOrganizer.Model.IAlbum>();
        }

        public override IEnumerable<AlbumArtOrganizer.Model.IAlbum> GetAlbums()
        {
            var optionRootDirectory = Options.FirstOrDefault(option => option is Model.OptionRootDirectory) as Model.OptionRootDirectory;
            System.IO.DirectoryInfo rootDirectory = null;
            if (optionRootDirectory != null)
            {
                rootDirectory = optionRootDirectory.Directory;
            }
            if (rootDirectory == null)
            {
                var pathsToTry = new List<string>()
                { 
                    Environment.GetFolderPath(Environment.SpecialFolder.MyMusic),
                    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                    Environment.GetFolderPath(Environment.SpecialFolder.Personal)
                };
                foreach(var path in pathsToTry)
                {
                    if (System.IO.File.Exists(path))
                    {
                        rootDirectory = new System.IO.DirectoryInfo(path);
                        break;
                    }
                }
                // TODO: If root directory is still null - log and throw exception?
            }

            var optionRegularExpression = Options.FirstOrDefault(option => option is Model.OptionRegularExpression) as Model.OptionRegularExpression;
            var regularExpressionString = String.Empty;
            if (optionRegularExpression != null)
            {
                regularExpressionString = optionRegularExpression.Value;
            }
            if (String.IsNullOrEmpty(regularExpressionString))
            {
                regularExpressionString = @"[A-Za-z0-9#]\\(?<artist>.*)\\(?<releasedate>.*) - (?<album>.*)";
            }

            var dirs = from dir in rootDirectory.EnumerateDirectories("*", System.IO.SearchOption.AllDirectories)
                       where !dir.EnumerateDirectories().Any()
                       select dir;
            var artistList = new List<AlbumArtOrganizer.Model.IArtist>();
            foreach (var dir in dirs)
            {
                var path = dir.FullName.Remove(0, rootDirectory.FullName.Length + 1);
                var regexp = new Regex(regularExpressionString);
                var match = regexp.Match(path);
                var artistName = match.Groups["artist"].Value;
                DateTime? releaseDate = null;
                try
                {
                    releaseDate = DateTime.Parse(match.Groups["releasedate"].Value);
                }
                catch (Exception)
                {
                    // TODO: Log that a release date could not be found?
                }
                var albumTitle = match.Groups["album"].Value;
                AlbumArtOrganizer.Model.ICoverImage coverImage = new Model.CoverImage()
                {
                    Path = System.IO.Path.Combine(dir.FullName, "Cover Front.jpg")
                };
                if (String.IsNullOrEmpty(artistName) && String.IsNullOrEmpty(albumTitle))
                {
                    // TODO: Add logging - the user might want to know (or at least be able to see) that this directory 
                    // never was included (possibly because the regex didn't match correctly)
                    continue;
                }
                AlbumArtOrganizer.Model.IArtist artist = null;
                if (!artistList.Any(a => a.Name == artistName))
                {
                    artist = new Model.Artist()
                    {
                        Name = artistName
                    };
                    artistList.Add(artist);
                }
                else
                {
                    artist = artistList.Find(a => a.Name == artistName);
                }
                var album = new Model.Album()
                {
                    Title = albumTitle,
                    ReleaseDate = releaseDate,
                    Artist = artist,
                    CoverImage = coverImage
                };
                artist.Albums.Add(album);
                _foundAlbums.Add(album);
                var reportProgressEventArgs = new AlbumArtOrganizer.AlbumScanner.AlbumScannerReportProgressEventArgs()
                {
                    Album = album,
                    FoundCount = _foundAlbums.Count
                };
                OnReportProgress(reportProgressEventArgs);
            }
            var completedEventArgs = new AlbumArtOrganizer.AlbumScanner.AlbumScannerCompletedEventArgs()
            {
                Albums = _foundAlbums
            };
            OnCompleted(completedEventArgs);
            return _foundAlbums;
        }

        public override void ReplaceCoverImage(AlbumArtOrganizer.Model.IAlbum album, AlbumArtOrganizer.Model.IImage image)
        {
            if (album is Model.Album)
            {
                var coverImage = album.CoverImage as Model.CoverImage;
                var webClient = new System.Net.WebClient();
                webClient.DownloadFile(image.FullSizeLocation, coverImage.Path);
                coverImage.PublishPathChangedNotfication();
            }
            else
            {
                throw new InvalidOperationException("Cannot call ReplaceCoverImage for FileSystem plug-in with an IAlbum implementation from another plug-in.");
            }
        }
    }
}
